Improve GtkBuilder error reporting
authorMatthias Clasen <mclasen@redhat.com>
Tue, 7 Apr 2009 00:13:35 +0000 (20:13 -0400)
committerMatthias Clasen <mclasen@redhat.com>
Tue, 7 Apr 2009 00:13:35 +0000 (20:13 -0400)
Make GtkBuilder report an error when it encounters a duplicate id,
instead of segfaulting later on

docs/reference/gtk/tmpl/gtkbuilder.sgml
gtk/gtkbuilder.h
gtk/gtkbuilderparser.c
gtk/gtkbuilderprivate.h

index 4353b1d2e33ff86d1757ca07a0e5a90f976f755a..09ee015f94bc6b6e7495a504d1daafa4bb192b30 100644 (file)
@@ -285,6 +285,7 @@ using #GtkBuilder.
     some attribute value.
 @GTK_BUILDER_ERROR_VERSION_MISMATCH: The input file requires a newer version
     of GTK+.
+@GTK_BUILDER_ERROR_DUPLICATE_ID: An object id occurred twice.
 
 <!-- ##### FUNCTION gtk_builder_new ##### -->
 <para>
index 4a11001c5c368ec37e576d6a71378907fe1f1fbe..0f9224e0e7c961bdc070c41336aa86c21b63927f 100644 (file)
@@ -52,7 +52,8 @@ typedef enum
   GTK_BUILDER_ERROR_INVALID_TAG,
   GTK_BUILDER_ERROR_MISSING_PROPERTY_VALUE,
   GTK_BUILDER_ERROR_INVALID_VALUE,
-  GTK_BUILDER_ERROR_VERSION_MISMATCH
+  GTK_BUILDER_ERROR_VERSION_MISMATCH,
+  GTK_BUILDER_ERROR_DUPLICATE_ID
 } GtkBuilderError;
 
 GQuark gtk_builder_error_quark (void);
index 44b10fa0369d0eed08f1c86bb8f964f34aa7db45..084c3622f8237cdbd2e14f2768cb796aeb3c4f50 100644 (file)
@@ -298,11 +298,12 @@ is_requested_object (const gchar *object,
 }
 
 static void
-parse_object (ParserData   *data,
-              const gchar  *element_name,
-              const gchar **names,
-              const gchar **values,
-              GError      **error)
+parse_object (GMarkupParseContext  *context,
+              ParserData           *data,
+              const gchar          *element_name,
+              const gchar         **names,
+              const gchar         **values,
+              GError              **error)
 {
   ObjectInfo *object_info;
   ChildInfo* child_info;
@@ -310,6 +311,7 @@ parse_object (ParserData   *data,
   gchar *object_class = NULL;
   gchar *object_id = NULL;
   gchar *constructor = NULL;
+  gint line, line2;
 
   child_info = state_peek_info (data, ChildInfo);
   if (child_info && strcmp (child_info->tag.name, "object") == 0)
@@ -335,10 +337,11 @@ parse_object (ParserData   *data,
           object_class = _get_type_by_symbol (values[i]);
           if (!object_class)
             {
-              g_set_error (error, GTK_BUILDER_ERROR, 
+              g_markup_parse_context_get_position (context, &line, NULL);
+              g_set_error (error, GTK_BUILDER_ERROR,
                            GTK_BUILDER_ERROR_INVALID_TYPE_FUNCTION,
-                           _("Invalid type function: `%s'"),
-                           values[i]);
+                           _("Invalid type function on line %d: '%s'"),
+                           line, values[i]);
               return;
             }
         }
@@ -389,6 +392,19 @@ parse_object (ParserData   *data,
 
   if (child_info)
     object_info->parent = (CommonInfo*)child_info;
+
+  g_markup_parse_context_get_position (context, &line, NULL);
+  line2 = GPOINTER_TO_INT (g_hash_table_lookup (data->object_ids, object_id));
+  if (line2 != 0)
+    {
+      g_set_error (error, GTK_BUILDER_ERROR,
+                   GTK_BUILDER_ERROR_DUPLICATE_ID,
+                           _("Duplicate object id '%s' on line %d (previously on line %d)"),
+                           object_id, line, line2);
+      return;
+    }
+
+  g_hash_table_insert (data->object_ids, object_id, GINT_TO_POINTER (line));
 }
 
 static void
@@ -848,7 +864,7 @@ start_element (GMarkupParseContext *context,
   if (strcmp (element_name, "requires") == 0)
     parse_requires (data, element_name, names, values, error);
   else if (strcmp (element_name, "object") == 0)
-    parse_object (data, element_name, names, values, error);
+    parse_object (context, data, element_name, names, values, error);
   else if (data->requested_objects && !data->inside_requested_object)
     {
       /* If outside a requested object, simply ignore this tag */
@@ -1145,6 +1161,7 @@ _gtk_builder_parser_parse_buffer (GtkBuilder   *builder,
   data->builder = builder;
   data->filename = filename;
   data->domain = g_strdup (domain);
+  data->object_ids = g_hash_table_new (g_str_hash, g_str_equal);
 
   data->requested_objects = NULL;
   if (requested_objs)
@@ -1204,6 +1221,7 @@ _gtk_builder_parser_parse_buffer (GtkBuilder   *builder,
   g_slist_foreach (data->requested_objects, (GFunc) g_free, NULL);
   g_slist_free (data->requested_objects);
   g_free (data->domain);
+  g_hash_table_destroy (data->object_ids);
   g_markup_parse_context_free (data->ctx);
   g_free (data);
 
index 8c69630d6c91f93e29544ac9432f276a0a8d2d8e..e633a28b5d646f5a8d2c03a783060f974020b9ea 100644 (file)
@@ -101,6 +101,8 @@ typedef struct {
   gboolean inside_requested_object;
   gint requested_object_level;
   gint cur_object_level;
+
+  GHashTable *object_ids;
 } ParserData;
 
 typedef GType (*GTypeGetFunc) (void);